package com.vilen.learn.java7.V4.V4_3_5;

import com.vilen.learn.java7.V4.Author;
import com.vilen.learn.java7.V4.Update;

import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * CountDownLatch用来严格控制两个线程之间发生的事情。
 如果用普通的List代替CopyOnWriteArrayList，结果会导致出现ConcurrentModificationException异常。
 这也是在两个线程之间共享一个Lock对象以控制对共享资源（即STDOUT）访问的例子。如果用块结构方式写这段代码，会显得更加杂乱。
 * Created by vilen on 2017/10/4.
 */
public class CopyOnWriteExampleMain {
    public static void main(String[] args) {
        final CountDownLatch firstLatch = new CountDownLatch(1);
        final CountDownLatch secondLatch = new CountDownLatch(1);
        final Update.Builder ub = new Update.Builder();
        //①设置初始状态
        final CopyOnWriteArrayList<Update> l = new CopyOnWriteArrayList<>();
        l.add(ub.author(new Author("Ben")).updateText("I like pie").build());
        l.add(ub.author(new Author("Charles")).updateText("I like ham on rye").build());

        Lock lock = new ReentrantLock();
        final MicroBlogTimeline tl1 = new MicroBlogTimeline("TL1", l, lock);
        final MicroBlogTimeline tl2 = new MicroBlogTimeline("TL2", l, lock);

        Thread t1 = new Thread(){
            @Override
            public void run() {
                l.add(ub.author(new Author("Jeffrey")).updateText("I like a lot of things").build());
                tl1.prep();
                firstLatch.countDown();
                //用锁存器严格限制事件的顺序（1）
                try {
                    secondLatch.await();
                } catch (InterruptedException e) {

                }
                tl1.printTimeline();
            }
        };
        Thread t2 = new Thread(){
            @Override
            public void run() {
                //用锁存器严格限制事件的顺序（2）
                try {
                    firstLatch.await();
                    l.add(ub.author(new Author("Gavin")).updateText("I like otters").build());
                    tl2.prep();
                    //用锁存器严格限制事件的顺序（3）
                    secondLatch.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                tl2.printTimeline();
            }
        };
        t1.start();
        t2.start();
    }
}
